/**
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.nhncorp.neptune.jdbc;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.SQLWarning;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;

import com.nhncorp.neptune.client.nql.javacc.NqlParser;
import com.nhncorp.neptune.client.nql.statement.ExecStatus;
import com.nhncorp.neptune.client.nql.statement.QueryStatement;
import com.nhncorp.neptune.client.nql.statement.SelectStatement;

/**
 * @author jindolk
 *
 */
public class NeptuneStatement implements Statement {
  NeptuneConnection conn;
  ResultSet resultSet;
  int updateCount;
  
  List<String> batchSqls = new ArrayList<String>();
  
  boolean closed;
  
  NeptuneStatement(NeptuneConnection conn) {
    this.conn = conn;
  }
  
  @Override
  public void addBatch(String sql) throws SQLException {
    batchSqls.add(sql);
  }

  @Override
  public void clearBatch() throws SQLException {
    batchSqls.clear();
  }

  @Override
  public void close() throws SQLException {
    if(resultSet != null) {
      resultSet.close();
    }
    closed = true;
  }

  @Override
  public boolean execute(String sql) throws SQLException {
    closed = false;
    resultSet = null;
    updateCount = 0;
    
    NqlParser parser = new NqlParser(sql);
    try {
      QueryStatement stmt = parser.parseStmt();
      ExecStatus status = stmt.execute(conn.getConf());
      if(status.getException() != null) {
        throw status.getException();
      }
      
      if(!status.isError()) {
        if(stmt instanceof SelectStatement) {
          resultSet = new NeptuneResultSet(this, status.getRowIterator());
        } else {
          updateCount = 1;
        }
        return true;
      } else {
        throw new SQLException(status.getException());
      }
      
    } catch (Exception e) {
      SQLException err = new SQLException(e.getMessage());
      err.initCause(e);
      throw err;
    }
  }

  @Override
  public int[] executeBatch() throws SQLException {
    int[] result = new int[batchSqls.size()];
    for(int i = 0; i < batchSqls.size(); i++) {
      boolean success = execute(batchSqls.get(i));
      if(success) {
        result[i] = 1;
      }
    }
    return result;
  }

  @Override
  public ResultSet executeQuery(String sql) throws SQLException {
    if(execute(sql)) {
      return resultSet;
    } else {
      return null;
    }
  }
  
  @Override
  public Connection getConnection() throws SQLException {
    return conn;
  }

  @Override
  public int executeUpdate(String sql) throws SQLException {
    boolean success = execute(sql);
    return success ? 1 : 0;
  }
  
  @Override
  public ResultSet getResultSet() throws SQLException {
    return resultSet;
  }

  @Override
  public int getUpdateCount() throws SQLException {
    return updateCount;
  }

  @Override
  public boolean isClosed() throws SQLException {
    return closed;
  }
  
  @Override
  public void cancel() throws SQLException {
    throw new SQLException("Not support cancel() operation");
  }

  @Override
  public void clearWarnings() throws SQLException {
    throw new SQLException("Not support clearWarnings() operation");
  }

  @Override
  public boolean execute(String sql, int autoGeneratedKeys) throws SQLException {
    throw new SQLException("Not support execute(String sql, int autoGeneratedKeys) operation");
  }

  @Override
  public boolean execute(String sql, int[] columnIndexes) throws SQLException {
    throw new SQLException("Not support execute(String sql, int[] columnIndexes) operation");
  }

  @Override
  public boolean execute(String sql, String[] columnNames) throws SQLException {
    throw new SQLException("Not support execute(String sql, String[] columnNames) operation");
  }

  @Override
  public int executeUpdate(String sql, int autoGeneratedKeys)
      throws SQLException {
    throw new SQLException("Not support executeUpdate(String sql, int autoGeneratedKeys) operation");
  }

  @Override
  public int executeUpdate(String sql, int[] columnIndexes) throws SQLException {
    throw new SQLException("Not support executeUpdate(String sql, int[] columnIndexes) operation");
  }

  @Override
  public int executeUpdate(String sql, String[] columnNames)
      throws SQLException {
    throw new SQLException("Not support executeUpdate(String sql, String[] columnNames) operation");
  }

  @Override
  public int getFetchDirection() throws SQLException {
    throw new SQLException("Not support getFetchDirection() operation");
  }

  @Override
  public int getFetchSize() throws SQLException {
    throw new SQLException("Not support getFetchSize() operation");
  }

  @Override
  public ResultSet getGeneratedKeys() throws SQLException {
    throw new SQLException("Not support getGeneratedKeys() operation");
  }

  @Override
  public int getMaxFieldSize() throws SQLException {
    throw new SQLException("Not support getMaxFieldSize() operation");
  }

  @Override
  public int getMaxRows() throws SQLException {
    throw new SQLException("Not support getMaxRows() operation");
  }

  @Override
  public boolean getMoreResults() throws SQLException {
    throw new SQLException("Not support getMoreResults() operation");
  }

  @Override
  public boolean getMoreResults(int current) throws SQLException {
    throw new SQLException("Not support getMoreResults() operation");
  }

  @Override
  public int getQueryTimeout() throws SQLException {
    throw new SQLException("Not support getQueryTimeout() operation");
  }

  @Override
  public int getResultSetConcurrency() throws SQLException {
    throw new SQLException("Not support getResultSetConcurrency() operation");
  }

  @Override
  public int getResultSetHoldability() throws SQLException {
    throw new SQLException("Not support getResultSetHoldability() operation");
  }

  @Override
  public int getResultSetType() throws SQLException {
    throw new SQLException("Not support getResultSetType() operation");
  }

  @Override
  public SQLWarning getWarnings() throws SQLException {
    throw new SQLException("Not support getWarnings() operation");
  }

  @Override
  public boolean isPoolable() throws SQLException {
    throw new SQLException("Not support isPoolable() operation");
  }

  @Override
  public void setCursorName(String name) throws SQLException {
    throw new SQLException("Not support setCursorName() operation");
  }

  @Override
  public void setEscapeProcessing(boolean enable) throws SQLException {
    throw new SQLException("Not support setEscapeProcessing() operation");
  }

  @Override
  public void setFetchDirection(int direction) throws SQLException {
    throw new SQLException("Not support setFetchDirection() operation");
  }

  @Override
  public void setFetchSize(int rows) throws SQLException {
    throw new SQLException("Not support setFetchSize() operation");
  }

  @Override
  public void setMaxFieldSize(int max) throws SQLException {
    throw new SQLException("Not support setMaxFieldSize() operation");
  }

  @Override
  public void setMaxRows(int max) throws SQLException {
    throw new SQLException("Not support setMaxRows() operation");
  }

  @Override
  public void setPoolable(boolean poolable) throws SQLException {
    throw new SQLException("Not support setPoolable() operation");
  }

  @Override
  public void setQueryTimeout(int seconds) throws SQLException {
    throw new SQLException("Not support setQueryTimeout() operation");
  }

  @Override
  public boolean isWrapperFor(Class<?> iface) throws SQLException {
    throw new SQLException("Not support isWrapperFor() operation");
  }

  @Override
  public <T> T unwrap(Class<T> iface) throws SQLException {
    throw new SQLException("Not support unwrap() operation");
  }
}
